﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.Runtime;
using Argos.WorkflowServices;
using Argos.Tracking;
using System.Workflow.Activities;
using Argos.Data.Model;
using Argos;
using Argos.Workflows;
using Argos.Diagnostics;
using System.Diagnostics;
using System.Threading;

namespace Argos.Hosting
{
	/// <summary>
	/// This class assists processes that are hosting monitoring workflows.
	/// </summary>
	/// <remarks>
	/// Instead of creating an instance of the <see cref="WorkflowRuntime"/> class and
	/// adding multiple services to that  instance, hosting processes can simply create
	/// an instance of this class instead.
	/// </remarks>
	public sealed class MonitoringRuntime : IDisposable
	{

		#region #ctor: public MonitoringRuntime(IAlertingService alertingService, ITestExecutionService testExecutionService)

		/// <summary>
		/// Creates a new instance of the class and specifies all the compulsory workflow
		/// services that are required to host monitoring workflows.
		/// </summary>
		/// <param name="alertingService">The alerting service.</param>
		/// <param name="testExecutionService">The test execution service.</param>
		/// <param name="storageService">The storage service. It is recommended that you implement this service by extending the <see cref="StorageServiceBase"/> class. This parameter cannot be null.</param>
		/// <exception cref="ArgumentNullExecption">The exception that is thrown if any of the arguments are <c>null</c>.</exception>
		public MonitoringRuntime(IAlertingService alertingService, ITestExecutionService testExecutionService, IStorageService storageService)
		{
			if (null == alertingService)
				throw new ArgumentNullException("alertingService");

			if (null == testExecutionService)
				throw new ArgumentNullException("testExecutionService");

			if (null == storageService)
				throw new ArgumentNullException("storageService");

			this.AddService(alertingService);
			this.AddService(testExecutionService);
			this.AddService(storageService);

			// "Touch" the tracking services to get them added to the runtime.

			object o = this.MonitoringWorkflowPropertyTrackingService;
			o = this.TargetInstanceTrackingService;
			o = this.TestActivityPropertyTrackingService;
		}

		#endregion



		#region public event EventHandler<MonitoringWorkflowStoppedEventArgs> MonitoringWorkflowStopped

		private EventHandler<MonitoringWorkflowStoppedEventArgs> MonitoringWorkflowStoppedHandler;

		/// <summary>
		/// Fired when a monitoring workflow is stopped.
		/// </summary>
		public event EventHandler<MonitoringWorkflowStoppedEventArgs> MonitoringWorkflowStopped
		{
			add { this.MonitoringWorkflowStoppedHandler += value; }
			remove { this.MonitoringWorkflowStoppedHandler -= value; }
		}

		#endregion

		#region public event EventHandler<MonitoringWorkflowTerminatedEventArgs> MonitoringWorkflowTerminated

		private EventHandler<MonitoringWorkflowTerminatedEventArgs> MonitoringWorkflowTerminatedHandler;

		/// <summary>
		/// Fired when a target monitoring workflow is terminated. The item on the
		/// arguments for this event is the ID of the target that terminated.
		/// </summary>
		public event EventHandler<MonitoringWorkflowTerminatedEventArgs> MonitoringWorkflowTerminated
		{
			add { this.MonitoringWorkflowTerminatedHandler += value; }
			remove { this.MonitoringWorkflowTerminatedHandler -= value; }
		}

		#endregion

		#region public event EventHandler<EventArgs> RunningMonitoringWorkflowCountChanged

		private EventHandler<EventArgs> RunningMonitoringWorkflowCountChangedHandler;

		/// <summary>
		/// Fired when <see cref="RunningMonitoringWorkflowCount"/> has changed.
		/// </summary>
		public event EventHandler<EventArgs> RunningMonitoringWorkflowCountChanged
		{
			add { this.RunningMonitoringWorkflowCountChangedHandler += value; }
			remove { this.RunningMonitoringWorkflowCountChangedHandler -= value; }
		}

		#endregion

		#region public event EventHandler<EventArgs> RunningTestActivityCountChanged

		private EventHandler<EventArgs> RunningTestActivityCountChangedHandler;

		/// <summary>
		/// Fired when <see cref="RunningTestActivityCount"/> has changed.
		/// </summary>
		public event EventHandler<EventArgs> RunningTestActivityCountChanged
		{
			add { this.RunningTestActivityCountChangedHandler += value; }
			remove { this.RunningTestActivityCountChangedHandler -= value; }
		}

		#endregion

		
		
		


		#region public IAlertingService AlertingService { get; }

		/// <summary>
		/// Returns an instance of the alerting service used.
		/// </summary>
		public IAlertingService AlertingService
		{
			get { return this.WorkflowRuntime.GetService<IAlertingService>(); }
		}

		#endregion

		#region public MonitoringWorkflowPropertyTrackingService MonitoringWorkflowPropertyTrackingService { get; }

		/// <summary>
		/// Returns the monitoring workflow property tracking service used.
		/// </summary>
		public MonitoringWorkflowPropertyTrackingService MonitoringWorkflowPropertyTrackingService
		{
			get
			{
				MonitoringWorkflowPropertyTrackingService svc = this.WorkflowRuntime.GetService<MonitoringWorkflowPropertyTrackingService>();
				if (null == svc)
				{
					svc = new MonitoringWorkflowPropertyTrackingService();
					this.AddService(svc);
				}
				return svc;
			}
		}

		#endregion

		#region public int RunningMonitoringWorkflowCount { get; private set; }

		private int _RunningMonitoringWorkflowCount;

		/// <summary>
		/// Returns the number of currently running monitoring workflows.
		/// </summary>
		public int RunningMonitoringWorkflowCount
		{
			get { return _RunningMonitoringWorkflowCount; }
			private set
			{
				if (!int.Equals(this.RunningMonitoringWorkflowCount, value))
				{
					_RunningMonitoringWorkflowCount = value;
					this.OnRunningMonitoringWorkflowCountChanged(EventArgs.Empty);
				}
			}
		}

		#endregion

		#region public int RunningTestActivityCount { get; private set; }

		private int _RunningTestActivityCount;

		/// <summary>
		/// Returns the number of currently running test activities.
		/// </summary>
		public int RunningTestActivityCount
		{
			get { return _RunningTestActivityCount; }
			private set
			{
				if (!int.Equals(this.RunningTestActivityCount, value))
				{
					_RunningTestActivityCount = value;
					this.OnRunningTestActivityCountChanged(EventArgs.Empty);
				}
			}
		}

		#endregion

		#region public StateTrackingService StateTrackingService { get; }

		/// <summary>
		/// Returns the state tracking service used.
		/// </summary>
		public StateTrackingService StateTrackingService
		{
			get
			{
				StateTrackingService svc = this.WorkflowRuntime.GetService<StateTrackingService>();
				if (null == svc)
				{
					svc = new StateTrackingService();
					this.AddService(svc);
				}
				return svc;
			}
		}

		#endregion

		#region public IStorageService StorageService { get; }

		/// <summary>
		/// Returns an instance of the storage service used.
		/// </summary>
		public IStorageService StorageService
		{
			get { return this.WorkflowRuntime.GetService<IStorageService>(); }
		}

		#endregion
		
		#region public TargetInstanceTrackingService TargetInstanceTrackingService { get; }

		/// <summary>
		/// Returns the target instance tracking service used.
		/// </summary>
		public TargetInstanceTrackingService TargetInstanceTrackingService
		{
			get
			{
				TargetInstanceTrackingService svc = this.WorkflowRuntime.GetService<TargetInstanceTrackingService>();
				if (null == svc)
				{
					svc = new TargetInstanceTrackingService();
					this.AddService(svc);
				}
				return svc;
			}
		}

		#endregion

		#region public TestActivityPropertyTrackingService TestActivityPropertyTrackingService { get; }

		/// <summary>
		/// Returns the test activity property tracking service used.
		/// </summary>
		public TestActivityPropertyTrackingService TestActivityPropertyTrackingService
		{
			get
			{
				TestActivityPropertyTrackingService svc = this.WorkflowRuntime.GetService<TestActivityPropertyTrackingService>();
				if (null == svc)
				{
					svc = new TestActivityPropertyTrackingService();
					this.AddService(svc);
				}
				return svc;
			}
		}

		#endregion
		
		#region public ITestExecutionService TestExecutionService { get; }

		/// <summary>
		/// Returns an instance of the test execution service used.
		/// </summary>
		public ITestExecutionService TestExecutionService
		{
			get { return this.WorkflowRuntime.GetService<ITestExecutionService>(); }
		}

		#endregion

		#region public WorkflowRuntime WorkflowRuntime { get; }

		private WorkflowRuntime _WorkflowRuntime;

		/// <summary>
		/// Returns the workflow runtime instance that the monitoring host class
		/// uses to run monitoring workflows with.
		/// </summary>
		public WorkflowRuntime WorkflowRuntime
		{
			get
			{
				if (null == _WorkflowRuntime)
				{
					_WorkflowRuntime = new WorkflowRuntime();
					_WorkflowRuntime.WorkflowAborted += this.WorkflowRuntime_WorkflowAborted;
					_WorkflowRuntime.WorkflowCompleted += this.WorkflowRuntime_WorkflowCompleted;
					_WorkflowRuntime.WorkflowCreated += this.WorkflowRuntime_WorkflowCreated;
					_WorkflowRuntime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowIdled);
					_WorkflowRuntime.WorkflowLoaded += new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowLoaded);
					_WorkflowRuntime.WorkflowPersisted += new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowPersisted);
					_WorkflowRuntime.WorkflowResumed += new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowResumed);
					_WorkflowRuntime.WorkflowStarted += this.WorkflowRuntime_WorkflowStarted;
					_WorkflowRuntime.WorkflowSuspended += new EventHandler<WorkflowSuspendedEventArgs>(WorkflowRuntime_WorkflowSuspended);
					_WorkflowRuntime.WorkflowTerminated += this.WorkflowRuntime_WorkflowTerminated;
					_WorkflowRuntime.WorkflowUnloaded += new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowUnloaded);
				}
				return _WorkflowRuntime;
			}
		}

		#endregion



		private object TargetInstanceIdLock = new object();
		private Dictionary<Guid, Guid> TargetInstanceIds = new Dictionary<Guid, Guid>();



		#region public void AddService(object service)

		/// <summary>
		/// Adds the given workflow service to the workflow runtime.
		/// </summary>
		/// <param name="service">The service to add.</param>
		/// <exception cref="ArgumentNullException">The exception that is thrown if <paramref name="service"/> is null.</exception>
		/// <exception cref="ArgumentException">The exception that is thrown if the given service is not a workflow service.</exception>
		public void AddService(object service)
		{
			if (null == service)
				throw new ArgumentNullException("service");

			if (!service.GetType().IsWorkflowService())
				throw new ArgumentException("The given service is not a workflow service.", "service");

			this.WorkflowRuntime.AddService(service);
		}

		#endregion

		#region public void AddTarget(Target target)

		/// <summary>
		/// Creates a monitoring workflow instance for the given target and starts it.
		/// </summary>
		/// <param name="target">The target for which to create a target monitoring workflow instance.</param>
		/// <exception cref="ArgumentNullException">The exception that is thrown if <paramref name="target"/> is null.</exception>
		/// <exception cref="InvalidOperationException">The exception that is throw if the given target has already been added to the monitoring host.</exception>
		public void AddTarget(Target target)
		{
			this.AddTarget(target, null);
		}

		#endregion

		#region public void AddTarget(Target target, object testState)

		/// <summary>
		/// Creates a monitoring workflow instance for the given target, sets the given state for
		/// the target's test, and starts the monitoring workflow instance.
		/// </summary>
		/// <param name="target">The target for which to create a target monitoring workflow instance.</param>
		/// <param name="testState">The previously stored state for the target's test. This parameter can be null.</param>
		/// <exception cref="ArgumentNullException">The exception that is thrown if <paramref name="target"/> is null.</exception>
		/// <exception cref="InvalidOperationException">The exception that is throw if the given target has already been added to the monitoring host.</exception>
		public void AddTarget(Target target, object testState)
		{
			if (null == target)
				throw new ArgumentNullException("target");

			if (this.TargetInstanceIds.ContainsKey(target.Id))
			{
				throw new InvalidOperationException("There is already a monitoring workflow instance for the given target.");
			}

			Dictionary<string, object> props = new Dictionary<string, object>(target.MonitoringWorkflowProperties);
			props["TargetId"] = target.Id;

			if (null != testState && target.MonitoringWorkflowType.ImplementsInterface(typeof(ITargetChangeMonitoringWorkflow)))
			{
				props["CurrentTestState"] = testState;
				props["PreviousTestState"] = testState;
			}

			WorkflowInstance instance = this.WorkflowRuntime.CreateWorkflow(target.MonitoringWorkflowType, props);
			this.TargetInstanceIds.Add(target.Id, instance.InstanceId);
			instance.Start();

			Tracer.TraceData(TraceEventType.Information, 0, "Started new monitoring workflow.", Tracer.CreateData("TargetId", target.Id), Tracer.CreateData("InstanceId", instance.InstanceId), Tracer.CreateData("TestState", testState));

		}

		#endregion
		
		#region public void Dispose()

		/// <summary>
		/// Disposes of resources held by the class instance.
		/// </summary>
		public void Dispose()
		{
			this.WorkflowRuntime.Dispose();
		}

		#endregion

		#region public Guid? GetInstanceId(Guid targetId)

		/// <summary>
		/// Returns the ID of the workflow instance that is monitoring the target
		/// with the given ID.
		/// </summary>
		/// <param name="targetId">The ID of the target whose monitoring workflow instance ID to return.</param>
		/// <returns>Returns the instnace ID. If no instance ID is found, <c>null</c> is returned.</returns>
		public Guid? GetInstanceId(Guid targetId)
		{
			Guid id = this.TargetInstanceIds.FirstOrDefault(p => p.Key == targetId).Value;
			if (id != Guid.Empty)
			{
				return id;
			}
			return null;
		}

		#endregion

		#region public T GetService<T>()

		/// <summary>
		/// Returns the service of the given type.
		/// </summary>
		/// <typeparam name="T">The type of service to return.</typeparam>
		public T GetService<T>()
		{
			return this.WorkflowRuntime.GetService<T>();
		}

		#endregion

		#region public Guid? GetTargetId(Guid instanceId)

		/// <summary>
		/// Returns the ID of the target that is being monitored by the monitoring workflow instance
		/// with the given ID.
		/// </summary>
		/// <param name="instanceId">The instance ID of the workflow instance whose monitored target ID to return.</param>
		/// <returns>Returns the target ID. If no target ID is found, <c>null</c> is returned.</returns>
		public Guid? GetTargetId(Guid instanceId)
		{
			Guid id = this.TargetInstanceIds.FirstOrDefault(p => p.Value == instanceId).Value;
			if (id != Guid.Empty)
			{
				return id;
			}
			return null;
		}

		#endregion

		#region public void RemoveTarget(Guid targetId)

		/// <summary>
		/// Stops the monitoring workflow instance monitoring the target with the given ID
		/// and removes that instance from the workflow runtime.
		/// </summary>
		/// <param name="targetId">The ID of the target to remove.</param>
		public void RemoveTarget(Guid targetId)
		{
			Guid? instanceId = this.GetInstanceId(targetId);
			if (instanceId.HasValue)
			{
				WaitCallback instanceKiller = (state) =>
				{
					WorkflowInstance instance = this.WorkflowRuntime.TryGetWorkflow(instanceId.Value);
					if (null != instance)
					{
						try
						{
							instance.Abort();
						}
						catch { }

						lock (this.TargetInstanceIdLock)
						{
							if (this.TargetInstanceIds.ContainsKey(targetId))
							{
								this.TargetInstanceIds.Remove(targetId);
							}
						}
					}
				};

				// Abort the instance on another thread to avoid blocking the
				// calling thread longer than necessary.
				ThreadPool.QueueUserWorkItem(instanceKiller);
			}
		}

		#endregion

		#region private void OnMonitoringWorkflowStopped(MonitoringWorkflowStoppedEventArgs e)

		/// <summary>
		/// Fires the <see cref="MonitoringWorkflowStopped"/> event.
		/// </summary>
		private void OnMonitoringWorkflowStopped(MonitoringWorkflowStoppedEventArgs e)
		{

			Tracer.TraceData(TraceEventType.Warning, 0, "A monitoring workflow was stopped. If a monitoring workflow was not intentionally stopped, this might indicate that a monitoring workflow has incorrectly completed.", Tracer.CreateData("TargetId", e.TargetId), Tracer.CreateData("InstanceId", e.WorkflowInstanceId));
			if (null != this.MonitoringWorkflowStoppedHandler)
			{
				this.MonitoringWorkflowStoppedHandler.Invoke(this, e);
			}
		}

		#endregion

		#region private void OnMonitoringWorkflowTerminated(MonitoringWorkflowTerminatedEventArgs e)

		/// <summary>
		/// Fires the <see cref="MonitoringWorkflowTerminated"/> event.
		/// </summary>
		private void OnMonitoringWorkflowTerminated(MonitoringWorkflowTerminatedEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Critical, 0, "A monitoring workflow terminated unexpectedly.", Tracer.CreateData("TargetId", e.TargetId), Tracer.CreateData("InstanceId", e.WorkflowInstanceId), e.Exception);

			if (null != this.MonitoringWorkflowTerminatedHandler)
			{
				this.MonitoringWorkflowTerminatedHandler.Invoke(this, e);
			}
		}

		#endregion

		#region private void OnRunningMonitoringWorkflowCountChanged(EventArgs e)

		/// <summary>
		/// Fires the <see cref="RunningMonitoringWorkflowCountChanged"/> event.
		/// </summary>
		private void OnRunningMonitoringWorkflowCountChanged(EventArgs e)
		{
			if (null != this.RunningMonitoringWorkflowCountChangedHandler)
			{
				this.RunningMonitoringWorkflowCountChangedHandler.Invoke(this, e);
			}
		}

		#endregion

		#region private void OnRunningTestActivityCountChanged(EventArgs e)

		/// <summary>
		/// Fires the <see cref="RunningTestActivityCountChanged"/> event.
		/// </summary>
		private void OnRunningTestActivityCountChanged(EventArgs e)
		{
			if (null != this.RunningTestActivityCountChangedHandler)
			{
				this.RunningTestActivityCountChangedHandler.Invoke(this, e);
			}
		}

		#endregion

		#region private void SetWorkflowCounts()

		private object WorkflowCountLock = new object();

		private void SetWorkflowCounts()
		{
			int monitorCount = 0, testCount = 0;

			lock (this.WorkflowCountLock)
			{
				try
				{
					foreach (var instance in this.WorkflowRuntime.GetLoadedWorkflows())
					{
						if (instance.GetWorkflowDefinition().GetType().IsTargetMonitoringWorkflow())
						{
							monitorCount++;
						}
						if (instance.GetWorkflowDefinition().GetType().IsTestActivity())
						{
							testCount++;
						}
					}
				}
				catch { }
			}

			this.RunningMonitoringWorkflowCount = monitorCount;
			this.RunningTestActivityCount = testCount;
		}

		#endregion
		
		#region private void WorkflowRuntime_WorkflowAborted(object sender, WorkflowEventArgs e)

		private void WorkflowRuntime_WorkflowAborted(object sender, WorkflowEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Information, 0, "Workflow instance aborted.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)

		private void WorkflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Verbose, 0, "Workflow instance completed.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			Guid? targetId = this.GetTargetId(e.WorkflowInstance.InstanceId);
			if (targetId.HasValue)
			{
				this.OnMonitoringWorkflowStopped(new MonitoringWorkflowStoppedEventArgs(targetId.Value, e.WorkflowInstance.InstanceId));
				this.TargetInstanceIds.Remove(targetId.Value);
			}
			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowCreated(object sender, WorkflowEventArgs e)

		private void WorkflowRuntime_WorkflowCreated(object sender, WorkflowEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Verbose, 0, "Workflow instance created.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowIdled(object sender, WorkflowEventArgs e)

		private void WorkflowRuntime_WorkflowIdled(object sender, WorkflowEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Verbose, 0, "Workflow instance idled.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowLoaded(object sender, WorkflowEventArgs e)

		private void WorkflowRuntime_WorkflowLoaded(object sender, WorkflowEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Verbose, 0, "Workflow instance loaded.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowPersisted(object sender, WorkflowEventArgs e)

		private void WorkflowRuntime_WorkflowPersisted(object sender, WorkflowEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Information, 0, "Workflow instance persisted.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));
			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowResumed(object sender, WorkflowEventArgs e)

		private void WorkflowRuntime_WorkflowResumed(object sender, WorkflowEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Verbose, 0, "Workflow instance resumed.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowStarted(object sender, WorkflowEventArgs e)

		private void WorkflowRuntime_WorkflowStarted(object sender, WorkflowEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Verbose, 0, "Workflow instance started.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowSuspended(object sender, WorkflowSuspendedEventArgs e)

		private void WorkflowRuntime_WorkflowSuspended(object sender, WorkflowSuspendedEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Verbose, 0, "Workflow instance suspended.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)

		private void WorkflowRuntime_WorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Error, 0, "Workflow instance terminated.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId), e.Exception);

			Guid? targetId = this.GetTargetId(e.WorkflowInstance.InstanceId);
			if (targetId.HasValue)
			{

				if (targetId.Value == e.WorkflowInstance.InstanceId)
				{
					Tracer.TraceData(TraceEventType.Error, 0, "Target ID cannot equal the workflow instance ID. This very likely indicates of an error somewhere in the application.", Tracer.CreateData("TargetId", targetId.Value), Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));
				}

				this.OnMonitoringWorkflowTerminated(new MonitoringWorkflowTerminatedEventArgs(targetId.Value, e.WorkflowInstance.InstanceId, e.Exception));
				this.TargetInstanceIds.Remove(targetId.Value);
			}
			this.SetWorkflowCounts();
		}

		#endregion

		#region private void WorkflowRuntime_WorkflowUnloaded(object sender, WorkflowEventArgs e)

		private void WorkflowRuntime_WorkflowUnloaded(object sender, WorkflowEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Verbose, 0, "Workflow instance loaded.", Tracer.CreateData("InstanceId", e.WorkflowInstance.InstanceId));

			this.SetWorkflowCounts();
		}

		#endregion

	}
}
